package at.ptasat.solver.process;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import at.ptasat.solver.AsyncSolver;
import at.ptasat.solver.AsyncSolverListener;

final class AsyncProcessSolver extends AsyncSolver {

	private static final String JAVA = "java";
	private static final String[] VM_ARGUMENTS = (("-" + (AsyncProcessSolver.class.desiredAssertionStatus() ? "e" : "d") + "a") + " -jar tasat.jar").split(" ");

	private Thread worker;
	private Process process;
	private PollingRedirection outRedirection, errRedirection;

	public AsyncProcessSolver(int id, AsyncSolverListener callback, OutputStream out, OutputStream err, String argument) {
		super(id, callback, out, err, argument);
		worker = null;
		process = null;
	}

	@Override
	public void start(String additionalArgumentsString, File file) throws Exception {
		String[] arguments = getArguments().split(" ");
		String[] additionalArguments = additionalArgumentsString.split(" ");
		String[] command = new String[1 + VM_ARGUMENTS.length + additionalArguments.length + arguments.length + 1];
		int index = 0;
		command[index++] = JAVA;
		for (int i = 0; i < VM_ARGUMENTS.length; i++) {
			command[index++] = VM_ARGUMENTS[i];
		}
		for (int i = 0; i < additionalArguments.length; i++) {
			command[index++] = additionalArguments[i];
		}
		for (int i = 0; i < arguments.length; i++) {
			command[index++] = arguments[i];
		}
		command[index++] = file.getAbsolutePath();
		assert index == command.length;

		ProcessBuilder builder = new ProcessBuilder(command);
		builder.directory(new File(System.getProperty("user.dir")));
		process = builder.start();
		outRedirection = new PollingRedirection(process.getInputStream(), getOut(), getId() + " out");
		errRedirection = new PollingRedirection(process.getErrorStream(), getErr(), getId() + " err");

		Runnable run = new Runnable() {
			@Override
			public void run() {
				try {
					int exit = process.waitFor();
					if (exit == 0) {
						fireSolved();
					} else {
						fireFailed();
					}
				} catch (InterruptedException e) {
					Thread.currentThread().interrupt();
				}
			}
		};
		worker = new Thread(run);
		worker.start();
	}

	@Override
	public void kill() {
		if (worker != null && worker.isAlive()) {
			worker.interrupt();
			worker = null;
		}
		if (process != null) {
			process.destroy();
			try {
				outRedirection.close();
			} catch (IOException e) {
				// nothing to do
			} catch (InterruptedException e) {
				// nothing to do
			}
			try {
				errRedirection.close();
			} catch (IOException e) {
				// nothing to do
			} catch (InterruptedException e) {
				// nothing to do
			}
			outRedirection = null;
			errRedirection = null;
			process = null;
		}
	}

}
